/*
 * Hello Minecraft! Launcher.
 * Copyright (C) 2013  huangyuhui <huanghongxun2008@126.com>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see {http://www.gnu.org/licenses/}.
 */
package org.jackhuang.hmcl.laf.utils;

/*
 * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

 /*
 * <p>These classes are designed to be used while the
 * corresponding <code>LookAndFeel</code> class has been installed
 * (<code>UIManager.setLookAndFeel(new <i>XXX</i>LookAndFeel())</code>).
 * Using them while a different <code>LookAndFeel</code> is installed
 * may produce unexpected results, including exceptions.
 * Additionally, changing the <code>LookAndFeel</code>
 * maintained by the <code>UIManager</code> without updating the
 * corresponding <code>ComponentUI</code> of any
 * <code>JComponent</code>s may also produce unexpected results,
 * such as the wrong colors showing up, and is generally not
 * encouraged.
 *
 */
import java.awt.*;
import java.util.*;

import javax.swing.*;

/**
 * Implements Windows Parts and their States and Properties for the Windows Look and Feel.
 *
 * See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/userex/topics/partsandstates.asp
 * See tmschema.h (or vssym32.h & vsstyle.h for MS Vista)
 *
 * @author Leif Samuelsson
 */
public class TMSchema {

    /**
     * An enumeration of the various Windows controls (also known as
     * components, or top-level parts)
     */
    public static enum Control {
        BUTTON,
        COMBOBOX,
        EDIT,
        HEADER,
        LISTBOX,
        LISTVIEW,
        MENU,
        PROGRESS,
        REBAR,
        SCROLLBAR,
        SPIN,
        TAB,
        TOOLBAR,
        TRACKBAR,
        TREEVIEW,
        WINDOW
    }

    /**
     * An enumeration of the Windows compoent parts
     */
    public static enum Part {
        MENU(Control.MENU, 0), // Special case, not in native
        MP_BARBACKGROUND(Control.MENU, 7),
        MP_BARITEM(Control.MENU, 8),
        MP_POPUPBACKGROUND(Control.MENU, 9),
        MP_POPUPBORDERS(Control.MENU, 10),
        MP_POPUPCHECK(Control.MENU, 11),
        MP_POPUPCHECKBACKGROUND(Control.MENU, 12),
        MP_POPUPGUTTER(Control.MENU, 13),
        MP_POPUPITEM(Control.MENU, 14),
        MP_POPUPSEPARATOR(Control.MENU, 15),
        MP_POPUPSUBMENU(Control.MENU, 16),
        BP_PUSHBUTTON(Control.BUTTON, 1),
        BP_RADIOBUTTON(Control.BUTTON, 2),
        BP_CHECKBOX(Control.BUTTON, 3),
        BP_GROUPBOX(Control.BUTTON, 4),
        CP_COMBOBOX(Control.COMBOBOX, 0),
        CP_DROPDOWNBUTTON(Control.COMBOBOX, 1),
        CP_BACKGROUND(Control.COMBOBOX, 2),
        CP_TRANSPARENTBACKGROUND(Control.COMBOBOX, 3),
        CP_BORDER(Control.COMBOBOX, 4),
        CP_READONLY(Control.COMBOBOX, 5),
        CP_DROPDOWNBUTTONRIGHT(Control.COMBOBOX, 6),
        CP_DROPDOWNBUTTONLEFT(Control.COMBOBOX, 7),
        CP_CUEBANNER(Control.COMBOBOX, 8),
        EP_EDIT(Control.EDIT, 0),
        EP_EDITTEXT(Control.EDIT, 1),
        HP_HEADERITEM(Control.HEADER, 1),
        HP_HEADERSORTARROW(Control.HEADER, 4),
        LBP_LISTBOX(Control.LISTBOX, 0),
        LVP_LISTVIEW(Control.LISTVIEW, 0),
        PP_PROGRESS(Control.PROGRESS, 0),
        PP_BAR(Control.PROGRESS, 1),
        PP_BARVERT(Control.PROGRESS, 2),
        PP_CHUNK(Control.PROGRESS, 3),
        PP_CHUNKVERT(Control.PROGRESS, 4),
        RP_GRIPPER(Control.REBAR, 1),
        RP_GRIPPERVERT(Control.REBAR, 2),
        SBP_SCROLLBAR(Control.SCROLLBAR, 0),
        SBP_ARROWBTN(Control.SCROLLBAR, 1),
        SBP_THUMBBTNHORZ(Control.SCROLLBAR, 2),
        SBP_THUMBBTNVERT(Control.SCROLLBAR, 3),
        SBP_LOWERTRACKHORZ(Control.SCROLLBAR, 4),
        SBP_UPPERTRACKHORZ(Control.SCROLLBAR, 5),
        SBP_LOWERTRACKVERT(Control.SCROLLBAR, 6),
        SBP_UPPERTRACKVERT(Control.SCROLLBAR, 7),
        SBP_GRIPPERHORZ(Control.SCROLLBAR, 8),
        SBP_GRIPPERVERT(Control.SCROLLBAR, 9),
        SBP_SIZEBOX(Control.SCROLLBAR, 10),
        SPNP_UP(Control.SPIN, 1),
        SPNP_DOWN(Control.SPIN, 2),
        TABP_TABITEM(Control.TAB, 1),
        TABP_TABITEMLEFTEDGE(Control.TAB, 2),
        TABP_TABITEMRIGHTEDGE(Control.TAB, 3),
        TABP_PANE(Control.TAB, 9),
        TP_TOOLBAR(Control.TOOLBAR, 0),
        TP_BUTTON(Control.TOOLBAR, 1),
        TP_SEPARATOR(Control.TOOLBAR, 5),
        TP_SEPARATORVERT(Control.TOOLBAR, 6),
        TKP_TRACK(Control.TRACKBAR, 1),
        TKP_TRACKVERT(Control.TRACKBAR, 2),
        TKP_THUMB(Control.TRACKBAR, 3),
        TKP_THUMBBOTTOM(Control.TRACKBAR, 4),
        TKP_THUMBTOP(Control.TRACKBAR, 5),
        TKP_THUMBVERT(Control.TRACKBAR, 6),
        TKP_THUMBLEFT(Control.TRACKBAR, 7),
        TKP_THUMBRIGHT(Control.TRACKBAR, 8),
        TKP_TICS(Control.TRACKBAR, 9),
        TKP_TICSVERT(Control.TRACKBAR, 10),
        TVP_TREEVIEW(Control.TREEVIEW, 0),
        TVP_GLYPH(Control.TREEVIEW, 2),
        WP_WINDOW(Control.WINDOW, 0),
        WP_CAPTION(Control.WINDOW, 1),
        WP_MINCAPTION(Control.WINDOW, 3),
        WP_MAXCAPTION(Control.WINDOW, 5),
        WP_FRAMELEFT(Control.WINDOW, 7),
        WP_FRAMERIGHT(Control.WINDOW, 8),
        WP_FRAMEBOTTOM(Control.WINDOW, 9),
        WP_SYSBUTTON(Control.WINDOW, 13),
        WP_MDISYSBUTTON(Control.WINDOW, 14),
        WP_MINBUTTON(Control.WINDOW, 15),
        WP_MDIMINBUTTON(Control.WINDOW, 16),
        WP_MAXBUTTON(Control.WINDOW, 17),
        WP_CLOSEBUTTON(Control.WINDOW, 18),
        WP_MDICLOSEBUTTON(Control.WINDOW, 20),
        WP_RESTOREBUTTON(Control.WINDOW, 21),
        WP_MDIRESTOREBUTTON(Control.WINDOW, 22);

        private final Control control;
        private final int value;

        private Part(Control control, int value) {
            this.control = control;
            this.value = value;
        }

        public int getValue() {
            return value;
        }

        public String getControlName(Component component) {
            String str = "";
            if (component instanceof JComponent) {
                JComponent c = (JComponent) component;
                String subAppName = (String) c.getClientProperty("XPStyle.subAppName");
                if (subAppName != null)
                    str = subAppName + "::";
            }
            return str + control.toString();
        }

        @Override
        public String toString() {
            return control.toString() + "." + name();
        }
    }

    /**
     * An enumeration of the possible component states
     */
    public static enum State {
        ACTIVE,
        ASSIST,
        BITMAP,
        CHECKED,
        CHECKEDDISABLED,
        CHECKEDHOT,
        CHECKEDNORMAL,
        CHECKEDPRESSED,
        CHECKMARKNORMAL,
        CHECKMARKDISABLED,
        BULLETNORMAL,
        BULLETDISABLED,
        CLOSED,
        DEFAULT,
        DISABLED,
        DISABLEDHOT,
        DISABLEDPUSHED,
        DOWNDISABLED,
        DOWNHOT,
        DOWNNORMAL,
        DOWNPRESSED,
        FOCUSED,
        ROLLOVER,
        ROLLOVERCHECKED,
        ICONHOT,
        ICONNORMAL,
        ICONPRESSED,
        ICONSORTEDHOT,
        ICONSORTEDNORMAL,
        ICONSORTEDPRESSED,
        INACTIVE,
        INACTIVENORMAL, // See note 1
        INACTIVEHOT, // See note 1
        INACTIVEPUSHED, // See note 1
        INACTIVEDISABLED, // See note 1
        LEFTDISABLED,
        LEFTHOT,
        LEFTNORMAL,
        LEFTPRESSED,
        MIXEDDISABLED,
        MIXEDHOT,
        MIXEDNORMAL,
        MIXEDPRESSED,
        NORMAL,
        PRESSED,
        OPENED,
        PUSHED,
        READONLY,
        RIGHTDISABLED,
        RIGHTHOT,
        RIGHTNORMAL,
        RIGHTPRESSED,
        SELECTED,
        UNCHECKEDDISABLED,
        UNCHECKEDHOT,
        UNCHECKEDNORMAL,
        UNCHECKEDPRESSED,
        UPDISABLED,
        UPHOT,
        UPNORMAL,
        UPPRESSED,
        HOVER,
        UPHOVER,
        DOWNHOVER,
        LEFTHOVER,
        RIGHTHOVER,
        SORTEDDOWN,
        SORTEDHOT,
        SORTEDNORMAL,
        SORTEDPRESSED,
        SORTEDUP;

        /**
         * A map of allowed states for each Part
         */
        private static EnumMap<Part, State[]> stateMap;

        private static synchronized void initStates() {
            stateMap = new EnumMap<>(Part.class);

            stateMap.put(Part.EP_EDITTEXT,
                    new State[] {
                        NORMAL, ROLLOVER, SELECTED, DISABLED, FOCUSED, READONLY, ASSIST
                    });

            stateMap.put(Part.BP_PUSHBUTTON,
                    new State[] { NORMAL, ROLLOVER, PRESSED, DISABLED, DEFAULT });

            stateMap.put(Part.BP_RADIOBUTTON,
                    new State[] {
                        UNCHECKEDNORMAL, UNCHECKEDHOT, UNCHECKEDPRESSED, UNCHECKEDDISABLED,
                        CHECKEDNORMAL, CHECKEDHOT, CHECKEDPRESSED, CHECKEDDISABLED
                    });

            stateMap.put(Part.BP_CHECKBOX,
                    new State[] {
                        UNCHECKEDNORMAL, UNCHECKEDHOT, UNCHECKEDPRESSED, UNCHECKEDDISABLED,
                        CHECKEDNORMAL, CHECKEDHOT, CHECKEDPRESSED, CHECKEDDISABLED,
                        MIXEDNORMAL, MIXEDHOT, MIXEDPRESSED, MIXEDDISABLED
                    });

            State[] comboBoxStates = new State[] { NORMAL, ROLLOVER, PRESSED, DISABLED };
            stateMap.put(Part.CP_COMBOBOX, comboBoxStates);
            stateMap.put(Part.CP_DROPDOWNBUTTON, comboBoxStates);
            stateMap.put(Part.CP_BACKGROUND, comboBoxStates);
            stateMap.put(Part.CP_TRANSPARENTBACKGROUND, comboBoxStates);
            stateMap.put(Part.CP_BORDER, comboBoxStates);
            stateMap.put(Part.CP_READONLY, comboBoxStates);
            stateMap.put(Part.CP_DROPDOWNBUTTONRIGHT, comboBoxStates);
            stateMap.put(Part.CP_DROPDOWNBUTTONLEFT, comboBoxStates);
            stateMap.put(Part.CP_CUEBANNER, comboBoxStates);

            stateMap.put(Part.HP_HEADERITEM, new State[] { NORMAL, ROLLOVER, PRESSED,
                SORTEDNORMAL, SORTEDHOT, SORTEDPRESSED,
                ICONNORMAL, ICONHOT, ICONPRESSED,
                ICONSORTEDNORMAL, ICONSORTEDHOT, ICONSORTEDPRESSED });

            stateMap.put(Part.HP_HEADERSORTARROW,
                    new State[] { SORTEDDOWN, SORTEDUP });

            State[] scrollBarStates = new State[] { NORMAL, ROLLOVER, PRESSED, DISABLED, HOVER };
            stateMap.put(Part.SBP_SCROLLBAR, scrollBarStates);
            stateMap.put(Part.SBP_THUMBBTNVERT, scrollBarStates);
            stateMap.put(Part.SBP_THUMBBTNHORZ, scrollBarStates);
            stateMap.put(Part.SBP_GRIPPERVERT, scrollBarStates);
            stateMap.put(Part.SBP_GRIPPERHORZ, scrollBarStates);

            stateMap.put(Part.SBP_ARROWBTN,
                    new State[] {
                        UPNORMAL, UPHOT, UPPRESSED, UPDISABLED,
                        DOWNNORMAL, DOWNHOT, DOWNPRESSED, DOWNDISABLED,
                        LEFTNORMAL, LEFTHOT, LEFTPRESSED, LEFTDISABLED,
                        RIGHTNORMAL, RIGHTHOT, RIGHTPRESSED, RIGHTDISABLED,
                        UPHOVER, DOWNHOVER, LEFTHOVER, RIGHTHOVER
                    });

            State[] spinnerStates = new State[] { NORMAL, ROLLOVER, PRESSED, DISABLED };
            stateMap.put(Part.SPNP_UP, spinnerStates);
            stateMap.put(Part.SPNP_DOWN, spinnerStates);

            stateMap.put(Part.TVP_GLYPH, new State[] { CLOSED, OPENED });

            State[] frameButtonStates = new State[] {
                NORMAL, ROLLOVER, PUSHED, DISABLED, // See note 1
                INACTIVENORMAL, INACTIVEHOT, INACTIVEPUSHED, INACTIVEDISABLED, };
            // Note 1: The INACTIVE frame button states apply when the frame
            //         is inactive. They are not defined in tmschema.h

            // Fix for 6316538: Vista has five frame button states
            /*if (ThemeReader.getInt(Control.WINDOW.toString(),
                                   Part.WP_CLOSEBUTTON.getValue(), 1,
                                   Prop.IMAGECOUNT.getValue()) == 10) {
                frameButtonStates = new State[] {
                        NORMAL,         HOT,         PUSHED,         DISABLED,         null,
                        INACTIVENORMAL, INACTIVEHOT, INACTIVEPUSHED, INACTIVEDISABLED, null
                };
            }*/
            stateMap.put(Part.WP_MINBUTTON, frameButtonStates);
            stateMap.put(Part.WP_MAXBUTTON, frameButtonStates);
            stateMap.put(Part.WP_RESTOREBUTTON, frameButtonStates);
            stateMap.put(Part.WP_CLOSEBUTTON, frameButtonStates);

            // States for Slider (trackbar)
            stateMap.put(Part.TKP_TRACK, new State[] { NORMAL });
            stateMap.put(Part.TKP_TRACKVERT, new State[] { NORMAL });

            State[] sliderThumbStates
                    = new State[] { NORMAL, ROLLOVER, PRESSED, FOCUSED, DISABLED };
            stateMap.put(Part.TKP_THUMB, sliderThumbStates);
            stateMap.put(Part.TKP_THUMBBOTTOM, sliderThumbStates);
            stateMap.put(Part.TKP_THUMBTOP, sliderThumbStates);
            stateMap.put(Part.TKP_THUMBVERT, sliderThumbStates);
            stateMap.put(Part.TKP_THUMBRIGHT, sliderThumbStates);

            // States for Tabs
            State[] tabStates = new State[] { NORMAL, ROLLOVER, SELECTED, DISABLED, FOCUSED };
            stateMap.put(Part.TABP_TABITEM, tabStates);
            stateMap.put(Part.TABP_TABITEMLEFTEDGE, tabStates);
            stateMap.put(Part.TABP_TABITEMRIGHTEDGE, tabStates);

            stateMap.put(Part.TP_BUTTON,
                    new State[] {
                        NORMAL, ROLLOVER, PRESSED, DISABLED, CHECKED, ROLLOVERCHECKED
                    });

            State[] frameStates = new State[] { ACTIVE, INACTIVE };
            stateMap.put(Part.WP_WINDOW, frameStates);
            stateMap.put(Part.WP_FRAMELEFT, frameStates);
            stateMap.put(Part.WP_FRAMERIGHT, frameStates);
            stateMap.put(Part.WP_FRAMEBOTTOM, frameStates);

            State[] captionStates = new State[] { ACTIVE, INACTIVE, DISABLED };
            stateMap.put(Part.WP_CAPTION, captionStates);
            stateMap.put(Part.WP_MINCAPTION, captionStates);
            stateMap.put(Part.WP_MAXCAPTION, captionStates);

            stateMap.put(Part.MP_BARBACKGROUND,
                    new State[] { ACTIVE, INACTIVE });
            stateMap.put(Part.MP_BARITEM,
                    new State[] { NORMAL, ROLLOVER, PUSHED,
                        DISABLED, DISABLEDHOT, DISABLEDPUSHED });
            stateMap.put(Part.MP_POPUPCHECK,
                    new State[] { CHECKMARKNORMAL, CHECKMARKDISABLED,
                        BULLETNORMAL, BULLETDISABLED });
            stateMap.put(Part.MP_POPUPCHECKBACKGROUND,
                    new State[] { DISABLEDPUSHED, NORMAL, BITMAP });
            stateMap.put(Part.MP_POPUPITEM,
                    new State[] { NORMAL, ROLLOVER, DISABLED, DISABLEDHOT });
            stateMap.put(Part.MP_POPUPSUBMENU,
                    new State[] { NORMAL, DISABLED });

        }

        public static synchronized int getValue(Part part, State state) {
            if (stateMap == null)
                initStates();

            Enum[] states = stateMap.get(part);
            if (states != null)
                for (int i = 0; i < states.length; i++)
                    if (state == states[i])
                        return i + 1;

            if (state == null || state == State.NORMAL)
                return 1;

            return 0;
        }

        @Override
        public String toString() {
            return name().toLowerCase();
        }

    }

}
